package com.netty.server;

import com.netty.config.NettyConfig;
import com.netty.handler.HeartBeatHandler;
import com.netty.handler.WebSocketNettyHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author renyitong
 * @version 1.0.0
 * @createTime 2023年08月16日
 * @Description 这里面主要添加了编解码器和自定义入站规则和对WebSocket的支持
 */
@Component
@Slf4j
public class NettyWebSocketChannelInit extends ChannelInitializer<SocketChannel> {

    @Autowired
    private NettyConfig nettyConfig;

    @Autowired
    private WebSocketNettyHandler webSocketNettyHandler;


    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // 流水线管理通道中的处理程序（Handler），用来处理业务
        // webSocket协议本身是基于http协议的，所以这边也要使用http编解码器
        ch.pipeline().addLast(new HttpServerCodec());
        // 以块的方式来写的处理器
        ch.pipeline().addLast(new ChunkedWriteHandler());
        /*
         说明：
            1、http数据在传输过程中是分段的，HttpObjectAggregator可以将多个段聚合
            2、这就是为什么，当浏览器发送大量数据时，就会发送多次http请求
        */
        ch.pipeline().addLast(new HttpObjectAggregator(8192));

        //针对客户端，若10s内无读事件则触发心跳处理方法HeartBeatHandler#userEventTriggered
        ch.pipeline().addLast(new IdleStateHandler(10, 10, 0, TimeUnit.MINUTES));
        //自定义空闲状态检测(自定义心跳检测handler)
        ch.pipeline().addLast(new HeartBeatHandler());

        /*
        说明：
            1、对应webSocket，它的数据是以帧（frame）的形式传递
            2、浏览器请求时 ws://localhost:58080/xxx 表示请求的uri
            3、核心功能是将http协议升级为ws协议，保持长连接
        */
        ch.pipeline().addLast(new WebSocketServerProtocolHandler(nettyConfig.getPath(), "WebSocket", true, 65536 * 10));
        // 自定义的handler，处理业务逻辑
        ch.pipeline().addLast(webSocketNettyHandler);


    }
}
